/**
 * Package     core
 * @author     : wgy
 * @time       : 2024/5/13 星期一 下午 17:02
 * explain     ：jwt
**/

package jwts

import (
	"errors"
	"github.com/golang-jwt/jwt/v4"
	"time"
)

type JwtPayload struct {
	Uid    int `json:"uid"`
	RoleId int `json:"roleId"`
}

// CustomClaims 要在 JWT token 里面存放的数据
type CustomClaims struct {
	JwtPayload
	jwt.RegisteredClaims
}

var (
	TokenExpired = errors.New("token is expired")
	ErrInvalid   = errors.New("couldn't handle this token") //令牌无效
)

// GenerateToken 根据用户id生成token
func GenToken(payload JwtPayload, accessSecret string, accessExpire int64) (string, error) {
	c := CustomClaims{
		payload,
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(accessExpire))), //有效时间

		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	tokenString, err := token.SignedString([]byte(accessSecret))
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

// RefreshToken 更新token
func RefreshToken(tokenString string, accessSecret string, accessExpire int64) (string, error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(accessSecret), nil
	})
	if err != nil {
		return "", err
	}
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(accessExpire)))
		genToken, err := GenToken(claims.JwtPayload, accessSecret, accessExpire)
		if err != nil {
			return "", err
		}
		return genToken, nil
	}
	return "", ErrInvalid
}

// ParseToken 从tokenString中解析出claims
func ParseToken(tokenString string, accessSecret string) (*CustomClaims, error) {

	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(accessSecret), nil
	})
	if err != nil {
		return nil, TokenExpired
	}
	if token == nil {
		return nil, ErrInvalid
	}
	if claims, ok := token.Claims.(*CustomClaims); ok {
		return claims, nil
	} else {
		return nil, err
	}
}
